#!/bin/bash
##
#   Script to set the position of a moveable Conky
#
#   Written by @damo and @johnraff, November 2015
#   with major contributions by @xaos52

DIALOG="yad --center --undecorated --borders=20 \
--window-icon=distributor-logo-bunsenlabs"

unset CONKYPATH posX_1 posY_1 posX_2 posY_2 OFFSET_X OFFSET_Y gapX gapY

# makes array "config"
parse_conkyfile(){
    [[ -f $1 ]] || { echo "$1 is not a file." >&2;return 1;}
    unset config
    declare -Ag config
    local name value
    while read name value
    do
        [[ $name ]] || continue
        [[ $name = TEXT* ]] && break
        config["$name"]="$value"
    done < <(sed 's/\#.*$//' "$1")
}


# usage: edit_conkyfile file name=value [name2=value2...]
# use absolute path to file
# parse_conkyfile should already have been run
edit_conkyfile() {
    [[ "$1" = /* ]] || {
        echo "$0: $1 is not an absolute path." >&2
        return 1
    }
    file=$1
    shift
    local name value
    declare -ag sed_args
    while [[ $1 ]]; do
        unset name value sed_pattern sed_replace
        name="${1%%=*}"
        value="${1#*=}"
        shift
        [[ ${config["$name"]+x} ]] || {
            echo "$0: config key $name does not exist" >&2
            return 1
        }
        [[ ${config["$name"]//[[:space:]]} = "${value//[[:space:]]}" ]] && continue
        (( ${#sed_args[@]} == 0 )) && sed_args=("-ri")
        sed_pattern="^ *$name .*$"
        grep -q "#conkymove, original value for $name:" "$file" ||
            sed_replace="#conkymove, original value for $name: ${config[$name]}\n"
        sed_replace+="$name $value"
        sed_args+=("-e")
        sed_args+=("s/$sed_pattern/$sed_replace/")
    done
    (( ${#sed_args[@]} )) && sed "${sed_args[@]}" "$file"
}

function getStart(){    #   Get initial Conky position
    unset CONKYPATH
    unset info1
    declare -A info1
    while read line
    do
        unset key value
        [[ $line =~ Window\ id: ]] && {
            ID=${line#*id:}
            ID=${ID% \"*}
        }
        [[ $line != xwininfo:* && $line = *:* ]] && {
            key=${line%:*}
            value=${line#*:}
            info1[$key]=$value
        }
    done < <(xwininfo)
    # info now contains all the output of xwininfo

   CMD=$(xprop -id $ID  WM_COMMAND | awk -F '", "' '{
       cmd=$1
       sub(/^.*{ "/,"",cmd)
       for (i=1;i<=NF;i++)
        if($i ~ /-([a-zA-Z])?c/){
            i++
            sub(/\" }$/,"",$i)
            gsub(/\\\"/,"\"",$i)
            print cmd,$i
            exit
            }
       }'
       )

    if [[ ${CMD%% *} = conky ]];then
        echo "Found a conky"
        CONKYPATH=${CMD#* }
        posX_1=${info1[Absolute upper-left X]}
        posY_1=${info1[Absolute upper-left Y]}
    else
        echo "Selection is not a conky"
        $DIALOG --button="OK:0" --button="Exit:1" --text="Selection is not a conky\n\nChoose again?"
        if (( $? == 1 ));then
            echo "  Cancelled: exiting..."
            exit 0
        fi
        getStart
    fi
}

function getFinish(){   #   Get new Conky position
    unset info2
    declare -A info2
    while read line
    do
        unset key value
        [[ $line != xwininfo:* && $line = *:* ]] && {
            key=${line%:*}
            value=${line#*:}
            info2[$key]=$value
        }
    done < <(xwininfo -id $ID)
    posX_2=${info2[Absolute upper-left X]}
    posY_2=${info2[Absolute upper-left Y]}
}

function getOffset(){   # parse_conkyfile should already have been run
    if [[ ${config[alignment]} = none ]];then   # placement managed by Openbox
        TXT="This Conky has 'alignment none'\nso placement is handled by the Window Manager.\n"
        $DIALOG --text="$TXT" --button="OK"
        echo -e "\nConky has 'alignment none',\nso placement is handled by the Window Manager\nExiting...\n"
        exit 0
    fi

    OFFSET_X=$(( posX_2 - posX_1 ))
    OFFSET_Y=$(( posY_2 - posY_1 ))

    case ${config[alignment]} in
        tr|top_right|mr|middle_right|br|bottom_right|mm|middle_middle|bm|bottom_middle|tm|top_middle)
            gapX=$(( ${config[gap_x]} - OFFSET_X ))
            ;;
        tl|top_left|ml|middle_left|bl|bottom_left)
            gapX=$(( ${config[gap_x]} + OFFSET_X ))
            ;;
    esac
    case ${config[alignment]} in
        tr|top_right|tl|top_left|tm|top_middle)
            gapY=$(( ${config[gap_y]} + OFFSET_Y ))
            ;;
        br|bottom_right|bl|bottom_left|bm|bottom_middle|mm|middle_middle|ml|middle_left|mr|middle_right)
            gapY=$(( ${config[gap_y]} - OFFSET_Y ))
            ;;
    esac
}

## check necessary tools are installed
required_commands=(xwininfo xprop yad) # array, space-separated words

error_exit() {
    echo "$0 error: $1" >&2
    exit 1
}

missing_commands=()
for i in "${required_commands[@]}"
do
    hash $i || missing_commands+=(" $i")
done
[[ ${missing_commands[0]} ]] && error_exit "This script requires the following commands: ${missing_commands[*]}
Please install the packages containing the missing commands
and rerun the script."


$DIALOG --text="Click 'Select Conky' to pick a conky.\n\nThen use the 'xwininfo' cursor on the chosen conky\nto record its position." \
     --button="Select Conky:0" --button="yad-cancel:1"

if (( $? == 0 ));then
    getStart
else
    echo "  Cancelled: exiting..."
    exit 0
fi

$DIALOG --text="Move the Conky to the desired location\nwith Alt+L-mousebutton Drag.\n\nClick 'OK' to set the new position." \
     --button="OK:0" --button="yad-cancel:1"

if (( $? == 0 ));then
    getFinish
else
    echo "  Cancelled: exiting..."
    exit 0
fi

parse_conkyfile "$CONKYPATH"

getOffset

edit_conkyfile "$CONKYPATH" "gap_x"=$gapX "gap_y"=$gapY

exit 0
